import React, { ReactElement, useState, useEffect, useRef } from "react";
import classNames from 'classnames'
import Input, { InputProps } from './input'
import Icon from '../icon'
import useDebounce from '../../hooks/useDebounce'
import Transition from '../transition/transition'
import useClickOutside from '../../hooks/useClickOutside'

export interface DataSourceObject {
    value: string
}
export type DataSourceType<T = {}> = T & DataSourceObject

export interface autoCompleteProps extends Omit<InputProps, 'onSelect'> {
    fetchSuggestions: (str: string) => DataSourceType[] | Promise<DataSourceType[]>,
    onSelect?: (item: DataSourceType) => void;
    renderOption?: (item: DataSourceType) => ReactElement

}


const AutoComplete: React.FC<autoCompleteProps> = (props) => {
    //props    
    const { fetchSuggestions, onSelect, value, renderOption, ...restProps } = props
    // state
    const [inputValue, setValue] = useState(value)//当前输入框的值 
    const [suggestions, setSuggestions] = useState<DataSourceObject[]>([])//渲染列表的数组
    const [loading, setLoading] = useState(false)//是否loading
    const debouncedValue = useDebounce(inputValue, 300)//节流
    const [currentIdx, setcurrentIdx] = useState(-1)//当前选中数组·里面的索引
    const [showDropdown, setShowDropdown] = useState(false)//是否显示整个数组
    const triggerSearch = useRef(false)
    const componentRef = useRef(null)
    useClickOutside(componentRef, () => { setSuggestions([]) })
    // useEffect 
    useEffect(() => {
        if (debouncedValue && triggerSearch.current) {
            const results = fetchSuggestions(debouncedValue)
            if (results instanceof Promise) {
                setLoading(true)
                results.then(data => {
                    setLoading(false)
                    setSuggestions(data)
                })
            } else {
                setSuggestions(results)
            }
            setShowDropdown(true)
        } else {
            setSuggestions([])
        }

    }, [debouncedValue, fetchSuggestions])
    // methods
    const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const val = e.target.value.trim()
        setValue(val)
        triggerSearch.current = true
    }
    const handleSelect = (item: DataSourceObject) => {
        onSelect && onSelect(item)
        setSuggestions([])
        setcurrentIdx(-1)
        setValue(item.value)
        triggerSearch.current = false
    }
    const highlight = (index: number) => {
        if (index < 0) index = 0
        if (index >= suggestions.length) {
            index = suggestions.length - 1
        }
        setcurrentIdx(index)
    }
    // 处理键盘上下esc enter建
    const handleKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {
        switch (e.key) {
            case "ArrowUp":
                highlight(currentIdx - 1)
                break;
            case "ArrowDown":
                highlight(currentIdx + 1)
                break;
            case "Escape":
                setShowDropdown(false)
                setcurrentIdx(-1)
                break;
            case "Enter":
                if (suggestions[currentIdx]) {
                    handleSelect(suggestions[currentIdx])
                }
                break;


            default:
                break;
        }
    }
    // render
    const renderTemplate = (item: DataSourceType) => {
        return renderOption ? renderOption(item) : item.value
    }
    const generateDropdown = () => {
        return (
            < Transition
                in={showDropdown || loading}
                animation="zoom-in-top"
                timeout={300}
                onExited={() => { setSuggestions([]) }}>
                <ul className="viking-suggestion-list">
                    {loading &&
                        <div className="suggstions-loading-icon">
                            <Icon icon="spinner" spin />
                        </div>
                    }
                    {suggestions.map((item, index) => {
                        const cnames = classNames('suggestion-item', {
                            'is-active': index === currentIdx
                        })
                        return (
                            <li key={index} onClick={() => handleSelect(item)} className={cnames}>
                                { renderTemplate(item)}
                            </li>
                        )
                    })}
                </ul>
            </Transition >
        )
    }

    return (
        <div className="viking-auto-complete" ref={componentRef}>
            <Input
                value={inputValue}
                onChange={handleChange}
                onKeyDown={(e) => handleKeyDown(e)}
                {...restProps}
            />
            {generateDropdown()}
        </div>
    )
}

export default AutoComplete